package com.bootdo.common.service.impl;

import com.bootdo.common.utils.R;
import com.bootdo.common.utils.ShiroUtils;
import com.bootdo.common.utils.StringUtils;
import com.bootdo.enums.SubscribeStatus;
import com.bootdo.system.dao.*;
import com.bootdo.system.domain.*;
import com.bootdo.util.DatePattern;
import com.bootdo.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class PatientService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private DeptDao deptDao;
    @Autowired
    private SubscribeRecordDao subscribeRecordDao;
    @Autowired
    private BreachRuleStatDao breachRuleStatDao;
    @Autowired
    private DocIntrDao docIntrDao;
    @Autowired
    private DocPbDao docPbDao;

    /**
     * 列表数据
     */
    public List<SubscribeRecordDO> list(String docName, Integer status){
        Long docUserId = null;
        if(StringUtils.isNotEmpty(docName)){
            UserDO docUser = userDao.getByName(docName.trim());
            if(docUser != null){
                docUserId = docUser.getUserId();
            }else{
                docUserId = -1L;
            }
        }
        Long userId = ShiroUtils.getUserId();
        List<SubscribeRecordDO> list = subscribeRecordDao.getByUserId(userId);
        List<SubscribeRecordDO> list1 = new ArrayList<>();
        for(SubscribeRecordDO item : list){
            if(docUserId != null && !item.getDocUserId().equals(docUserId)){
                continue;
            }
            if(status != null && status != -1 && !item.getStatus().equals(status)){
                continue;
            }
            list1.add(item);
        }
        for (SubscribeRecordDO item : list1) {
            // 查询医生
            UserDO userDO = userDao.get(item.getDocUserId());
            item.setDocName(userDO.getName());
            // 状态
            SubscribeStatus anEnum = SubscribeStatus.getEnum(item.getStatus());
            item.setStatusText(anEnum == null ? "" : anEnum.getDesc());
            // 就诊时间
            item.setSeeTimeText(DateUtils.toString(item.getSeeTime(), DatePattern.YMD_HMS));
            // 创建时间
            item.setCreateTimeText(DateUtils.toString(item.getCreateTime(), DatePattern.YMD_HMS));
        }
        return list1;
    }

    /**
     * 医生列表数据
     */
    public List<YuYueDocDO> list1(String keShi){
        List<YuYueDocDO> result = new ArrayList<>();
        List<Long> depIds = new ArrayList<>();
        if(StringUtils.isNotEmpty(keShi)){
            keShi = "%" + keShi.trim() + "%";
            List<DeptDO> byName = deptDao.getByName(keShi);
            for(DeptDO item : byName){
                depIds.add(item.getDeptId());
            }
        }else{
            depIds.add(null);
        }
        List<UserDO> list = new ArrayList<>();
        for(Long item : depIds){
            List<UserDO> doc = userDao.getDoc(61L, item); // 61L 代表医生角色
            list.addAll(doc);
        }
        for (UserDO item : list) {
            // 查询医生简介
            DocIntrDO docIntrDO = docIntrDao.get(item.getUserId());
            YuYueDocDO docDO = new YuYueDocDO();
            docDO.setUserId(item.getUserId());
            docDO.setDocName(item.getName());
            docDO.setZhuanChang(docIntrDO == null ? null : docIntrDO.getEn());
            docDO.setXueLi(docIntrDO == null ? null : docIntrDO.getlEn());
            docDO.setJianJie(docIntrDO == null ? null : docIntrDO.getIn());
            // 科室
            DeptDO deptDO = deptDao.get(item.getDeptId());
            docDO.setKeShi(deptDO == null ? null : deptDO.getName());
            result.add(docDO);
        }
        return result;
    }

    /**
     * 预约取号
     */
    @Transactional
    public R add(Long docUserId, Date seeTime){
        // 不能预约当日号源
        if(DateUtils.isSameDay(new Date(), seeTime)){
            return R.error("不可预约当日号源！");
        }
        // 校验
        R r = comconCheck(seeTime, 0);
        if(r != null){
            return r;
        }
        // 只能预约7日内的号源
        long diffDays = DateUtils.getDiffDays(new Date(), seeTime);
        if(diffDays <= 0 || diffDays > 7){
            return R.error("只能预约7日内的号源！");
        }
        // 获取用户
        Long userId = ShiroUtils.getUserId();
        UserDO userDO = userDao.get(userId);
        if(userDO == null){
            return R.error("用户不存在");
        }
        if(userDO.getIsAuth() == null || userDO.getIsAuth() == 0){
            return R.error("请先实名认证！");
        }
        // 获取医生
        UserDO docUser = userDao.get(docUserId);
        if(docUser == null){
            return R.error("医生不存在");
        }
        // 判断用户是不是黑名单
        if(userDO.getBlock() != null && userDO.getBlock() == 1){
            return R.error("黑名单用户，不允许预约挂号！");
        }
        // 判断 同一天 限挂三个科室号，一个科室限挂一个号
        Map<String,Object> map = new HashMap<>();
        map.put("userId", userId);
        map.put("startTime", DateUtils.getStartOfDay(seeTime));
        map.put("endTime", DateUtils.getEndOfDay(seeTime));
        List<SubscribeRecordDO> list = subscribeRecordDao.list1(map);
        if(list.size() >= 3){
            return R.error("同一天 限挂三个号");
        }
        for(SubscribeRecordDO item : list){
            UserDO userDO1 = userDao.get(item.getDocUserId());
            if(userDO1.getDeptId().equals(docUser.getDeptId()) && SubscribeStatus.One.getSign().equals(item.getStatus())){
                return R.error("同一天 一个科室限挂一个号");
            }
        }
        // 判断医生当日有没有排班
        DocPbDO docPbDao1 = docPbDao.get1(docUserId, DateUtils.toString(seeTime, DatePattern.YMD));
        if(docPbDao1 == null){
            return R.error("当日【" + docUser.getName() + "】医生没有排班，请预约其他医生！");
        }
        if(docPbDao1.getSurplus() <= 0){
            return R.error("当日【" + docUser.getName() + "】医生预约已满，请预约其他医生！");
        }
        String startTime = DateUtils.toString(docPbDao1.getStartTime(), DatePattern.YMD_HMS);
        String endTime = DateUtils.toString(docPbDao1.getEndTime(), DatePattern.YMD_HMS);
        if(seeTime.before(docPbDao1.getStartTime()) || seeTime.after(docPbDao1.getEndTime())){
            return R.error("不能预约！该医生的工作时间为" + startTime + " ~ " + endTime);
        }
        // 插入
        SubscribeRecordDO insert = new SubscribeRecordDO();
        insert.setUserId(userId);
        insert.setDocUserId(docUserId);
        insert.setStatus(0);
        insert.setSeeTime(seeTime);
        insert.setCreateTime(new Date());
        subscribeRecordDao.save(insert);

        DocPbDO update = new DocPbDO();
        update.setId(docPbDao1.getId());
        update.setSurplus(docPbDao1.getSurplus() - 1);
        docPbDao.update(update);

        return R.ok();
    }

    // 取消预约
    @Transactional
    public R cancel(Long id){
        // 查询是否存在
        SubscribeRecordDO subscribeRecordDO = subscribeRecordDao.get(id);
        if(subscribeRecordDO == null){
            return R.error("预约数据不存在");
        }
        // 不能取消今日预约
        if(DateUtils.isSameDay(new Date(), subscribeRecordDO.getSeeTime())){
            return R.error("不能取消当日预约！");
        }
        // 校验
        R r = comconCheck(subscribeRecordDO.getSeeTime(), 1);
        if(r != null){
            return r;
        }
        // 统计删除
        String date = DateUtils.toString(new Date(), DatePattern.YMD);
        BreachRuleStatDO breachRuleStatDO = breachRuleStatDao.get(subscribeRecordDO.getUserId(), date);
        if(breachRuleStatDO == null){
            // 新增
            breachRuleStatDO = new BreachRuleStatDO();
            breachRuleStatDO.setCancleTimes(1);
            breachRuleStatDO.setBreakTimes(0);
            breachRuleStatDO.setDate(date);
            breachRuleStatDO.setUserId(subscribeRecordDO.getUserId());
            breachRuleStatDao.save(breachRuleStatDO);
        }else{
            // 修改
            breachRuleStatDO.setCancleTimes(breachRuleStatDO.getCancleTimes() + 1);
            breachRuleStatDao.update(breachRuleStatDO);
        }
        // 如果 一个月取消预约 5 次， 将用户标记为黑名单
        if(breachRuleStatDO.getCancleTimes() >= 5){
            UserDO update = new UserDO();
            update.setUserId(subscribeRecordDO.getUserId());
            update.setBlock(1);
            userDao.update(update);
        }
        // 将号放回号池
        DocPbDO docPbDao1 = docPbDao.get1(subscribeRecordDO.getDocUserId(), DateUtils.toString(subscribeRecordDO.getSeeTime(), DatePattern.YMD));
        if(docPbDao1 != null){
            DocPbDO docPbDO = new DocPbDO();
            docPbDO.setId(docPbDao1.getId());
            docPbDO.setSurplus(docPbDao1.getSurplus() + 1);
            docPbDao.update(docPbDO);
        }
        // 修改预约状态
        SubscribeRecordDO update = new SubscribeRecordDO();
        update.setId(subscribeRecordDO.getId());
        update.setStatus(SubscribeStatus.Three.getSign());
        int update1 = subscribeRecordDao.update(update);
        if (update1 > 0){
            return R.ok();
        }
        return R.error();
    }

    // 管理员批量取消预约
    public R batchCancel(Long[] ids){
        for(Long id : ids){
            R r = cancel(id);
            if(!r.get("code").toString().equals("0")){
                return R.error();
            }
        }
        return R.ok();
    }

    // 预约 和 取消预约 要在每天的 08:00:00 到 17:00:00 之间
    // 预约 和 取消 明日号，则今日时间要在 14:00 之前
    private R comconCheck(Date seeTime, int sign){
        Date now = DateUtils.parse(seeTime, DatePattern.HMS);
        Date begin = DateUtils.parse("08:00:00", DatePattern.HMS);
        Date end = DateUtils.parse("17:00:00", DatePattern.HMS);
        if(begin.after(now) || end.before(now)){
            return R.error("请于每日08:00:00 ~ 17:00:00期间预约！");
        }
        if(DateUtils.isSameDay(new Date(), seeTime)){
            end = DateUtils.parse("14:00:00", DatePattern.HMS);
            if(end.before(now)){
                return sign == 0 ? R.error("预约明日号源，请于今日14:00:00前预约！") : R.error("取消明日预约，请于今日14:00:00前取消！");
            }
        }
        return null;
    }

}
